Notebook for cellpy batch processing

You can fill inn the MarkDown cells (the cells without "numbering") by double-clicking them. Also remember, press shift + enter to execute a cell.

A couple of useful links:

This notebook uses the following packages

  • python >= 3.6
  • cellpy >= 0.3.3
  • pandas
  • numpy
  • matplotlib
  • bokeh
  • pyviz (holoviews)

0. Setting up things properly

0.1 Installing cellpy

For this to work, you will have to have a version of cellpy satisfying the criteria in the paragraph above. You might have to do a pre-release install to get it or clone the github repository and install in developer-mode.

Installing a pre-release with pip.

pip install --upgrade --pre cellpy

(if this is the first time you install cellpy, you can skip the --upgrade option)

Installing after cloning using pip in developer-mode. Note that you have to be in the directory where you have put the cellpy package (where the setup.py file is), if not, using . as argument will not work and you will have to provide the full path to the setup.py file):

pip install -e .

0.2 Make sure you have a properly working config file

For cellpy to find stuff, it needs to know where to look. A config file exists for this purpose. It is typically located in your home directory (for mac and linux) or in your documents directory (for Windows) and has a name on this form (replacing "username" with your real username):

.cellpy_prms_username.conf

The file format is YAML (be aware that it cares about white spaces). The most important settings for this notebook are probably the Paths. Make sure they make sense (and that both the paths and the db_path filename exist) and edit it if necessary.

Here is how a typical file (at least the top of it) looks like:

---
Paths:
  cellpydatadir: cellpy_data/cellpyfiles
  db_filename: cellpy_db.xlsx
  db_path: cellpy_data/db
  filelogdir: cellpy_data/logs
  outdatadir: cellpy_data/out
  rawdatadir: cellpy_data/raw
  examplesdir: cellpy_data/examples
  notebookdir: cellpy_data/notebooks
  batchfiledir: cellpy_data/batchfiles
FileNames:
  file_name_format: YYYYMMDD_[NAME]EEE_CC_TT_RR
Db:
  db_type: simple_excel_reader
  db_table_name: db_table
  db_header_row: 0
  db_unit_row: 1
  db_data_start_row: 2
  ...

0.3 Database file

This notebook uses the cellpy batch utility. For it to work properly (or at all) you will have to provide it with a database. You can choose to implement a database and a loader your self. Currently, cellpy ships with a very simple database solution that hardly justifies its name as a database. It reads an excel-file where the first row acts as column headers, the second provides the type (e.g. string, bool, etc), and the rest provides the necessary information for each of the cells (one row pr. cell).

A sample excel file ("db-file") is provided with this example. You will need fill inn values manually, one row for each cell you want to load. Then you will have to put it in the database folder (as defined in your config file where it says db_file: in the Paths-section). The name of the file must also be the same as defined in the config-file (db_filename:, i.e cellpy_db.xlsx in the example config file snippet above).

When cellpy reads the file, it uses the batch column (see below) to select which rows (i.e. cells) to load. For example, if the "b01" batch column is the one you tell cellpy to use and you provide it with the name "casandras_experiment", it will only select the rows that has "casandras_experiment" in the "b01" column. You provide cellpy with the "lookup" name when you issue the batch.init command, for example:

b = batch.init("casandras_experiment", "cool_project", batch_col="b01")

You must always have the columns colored green filled out. And make sure that the id column (the first one in the example xlsx file) has a unique integer for each row (it is used as a "key" when looking up stuff from the file).

0.4 Files to read

Make sure that the names of your experiment-files (for example your .res files) are on the form date_something_that_describes_the_cell.res because this is the name-format supported at the moment (this is not strictly true, but just to be on the safe side...).

OK, thats all for now. Have a look at the source code in the github repository or

1. Key information about the current experiment

Experimental-id: xxx
Short-name: xxx
Project: project name
By: your name
Date: xx.xx.xxxx

2. Short summary of the experiment before processing

It is often helpful to formulate what you wanted to achieve with your experiment before actually going into depth of the data. I believe that it does not make you "biased" when processing your data, but instead sharpens your mind and motivates you to look more closely on your results. I might be wrong, off course. Then just skip filling in this part.

Main purpose

(State the main hypothesis for the current set of experiment)

Expected outcome

(What do you expect to find out? What kind of tests did you perform?)

Special considerations

(State if there are any special considerations for this experiment)

3. Processing data

Setting up everything


In [ ]:
import numpy as np
import matplotlib.pyplot as plt

import cellpy
from cellpy import prms
from cellpy import prmreader
from cellpy.utils import batch

%matplotlib inline

In [ ]:
## Uncomment this and run for checking your cellpy parameters.
# prmreader.info()

Creating pages and initialise the cellpy batch object

If you need to create Journal Pages, please provide appropriate names for the project and the experiment to allow cellpy to build the pages.


In [ ]:
# Please fill in here
project = "xxx"
name = "xxx"
batch_col = "b01"

Initialisation


In [ ]:
print(" INITIALISATION OF BATCH ".center(80, "="))
b = batch.init(name, project, batch_col=batch_col)

Set parameters


In [ ]:
# setting some prms
b.experiment.export_raw = False
# b.experiment.export_cycles = True
# b.experiment.export_ica = True

Run


In [ ]:
# load info from your db and write the journal pages
b.create_journal()

In [ ]:
# create the apropriate folders
b.paginate()

In [ ]:
# load the data (and save .csv-files if you have set export_(raw/cycles/ica) = True)
# (this might take some time)
b.update()

In [ ]:
# collect summary-data (e.g. charge capacity vs cycle number) from each cell and export to .csv-file(s).
b.combine_summaries()

4. Looking at the data


In [ ]:
# Plot the charge capacity and the C.E. (and resistance) vs. cycle number (standard plot)
b.plot_summaries()

In [ ]:
# Show the journal pages
b.pages

Using hvplot for plotting summaries


In [ ]:
import hvplot.pandas
import holoviews as hv

In [ ]:
# hvplot does not like infinities
s = b.summaries.replace([np.inf, -np.inf], np.nan)

In [ ]:
layout = s["coulombic_efficiency"].hvplot() + s["discharge_capacity"].hvplot() * s["charge_capacity"].hvplot()
layout.cols(1)

In [ ]:
s["cumulated_coulombic_efficiency"].hvplot()

Looking closer at some summary-plots


In [ ]:
discharge_capacity = b.summaries.discharge_capacity
charge_capacity = b.summaries.charge_capacity
coulombic_efficiency = b.summaries.coulombic_efficiency
ir_charge = b.summaries.ir_charge

In [ ]:
fig, (ax1, ax2) = plt.subplots(2, 1)
ax1.plot(discharge_capacity)
ax1.set_ylabel("capacity ")
ax2.plot(ir_charge)
ax2.set_xlabel("cycle")
ax2.set_ylabel("resistance")

5. Checking for more details per cycle

A. pick the CellpyData object for one of the cells


In [ ]:
# Lets check what cells we have
cell_labels = b.experiment.cell_names
cell_labels

In [ ]:
# OK, then I choose one of them
label = cell_labels[0]
data = b.experiment.data[label]

B. Get some voltage curves for some cycles and plot them

The method get_cap can be used to extract voltage curves.


In [ ]:
cap = data.get_cap(categorical_column=True)
cap.head()

In [ ]:
fig, ax = plt.subplots()
ax.plot(cap.capacity, cap.voltage)
ax.set_xlabel("capacity")
ax.set_ylabel("voltage")

In [ ]:
c4,v4 = data.get_cap(cycle=4, method="forth-and-forth")
c10,v10 = data.get_cap(cycle=10, method="forth-and-forth")
fig, ax = plt.subplots()
ax.set_xlabel("capacity")
ax.set_ylabel("voltage")
ax.plot(c4,v4, "ro", label="cycle 4")
ax.plot(c10,v10, "bs", label="cycle 22")
ax.legend();

Looking at some dqdv data

Get capacity cycles and make dqdv using the ica module


In [ ]:
from cellpy.utils import ica
v4, dqdv4 = ica.dqdv_cycle(
    data.get_cap(
        4, 
        categorical_column=True, 
        method = "forth-and-forth")
)

v10, dqdv10 = ica.dqdv_cycle(
    data.get_cap(
        10, 
        categorical_column=True, 
        method = "forth-and-forth")
)

plt.plot(v4,dqdv4, label="cycle 4")
plt.plot(v10, dqdv10, label="cycle 10")
plt.legend();

Put it in a for-loop for plotting many ica plots


In [ ]:
fig, ax = plt.subplots()
for cycle in data.get_cycle_numbers():
    d = data.get_cap(
            cycle, 
            categorical_column=True, 
            method = "forth-and-forth"
        )
    if not d.empty:
        v, dqdv = ica.dqdv_cycle(d)
        ax.plot(v, dqdv)
    else:
        print(f"cycle {cycle} seems to be missing or corrupted")

Get all the dqdv data in one go


In [ ]:
hv.extension('bokeh')

In [ ]:
tidy_ica = ica.dqdv_frames(data)
cycles = list(range(1,3)) + [10, 15]
tidy_ica = tidy_ica.loc[tidy_ica.cycle.isin(cycles), :]

In [ ]:
%%opts Curve [xlim=(0,1)] NdOverlay [legend_position='right']
#legend_cols=True]
curve4 = (hv.Curve(tidy_ica, kdims=['voltage'], vdims=['dq', 'cycle'], label="Incremental capacity plot")
          .groupby("cycle")
          .opts(
              style={"Curve": dict(color=hv.Palette("Viridis"))},
          )
          .overlay()
          .opts(
              width=800,
              height=500,
          )
         )
curve4

In [ ]: